package com.mxpio.erp.workshop.policy.impl;

import java.math.BigDecimal;
import java.util.*;

import com.mxpio.erp.common.ModuleUtils;
import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.jpa.model.Notice;
import com.mxpio.erp.common.jpa.model.NoticeLine;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.order.policy.AbstractBizOrderPolicy;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.order.service.OrderService;
import com.mxpio.erp.common.quality.entity.MoInQualityOrderLine;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpio.erp.common.workshop.entity.*;
import com.mxpio.erp.common.quality.entity.MoInQualityOrder;
import com.mxpioframework.common.util.BeanReflectionUtils;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.security.util.SecurityUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 生产订单报工执行策略
 * @author mxpio
 *
 */
public class DefaultExecuteMoPolicy extends AbstractBizOrderPolicy {
	
	private List<OrderExcuteLineVo> orderExcuteVos;

	private OrderService orderService;

	private OrderLineService orderLineService;
	
	public DefaultExecuteMoPolicy(List<OrderExcuteLineVo> orderExcuteVos,OrderService orderService,OrderLineService orderLineService) {
		this.orderExcuteVos = orderExcuteVos;
		this.orderService = orderService;
		this.orderLineService = orderLineService;
	}
	
	@Override
	public void execute(OrderContext context) {
		
	}
	@Override
	public void apply(OrderContext context) {
		if(beforeExecute(context)) {
			execute(context);
			ManufactureOrder order = (ManufactureOrder) context.getEntity();
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();

			String[] accessTypes = context.getAccessType().split(",");
			for(String accessType : accessTypes){
				// 遍历执行行 生成通知单
				Map<String, Notice> noticeMap = new HashMap<>();
				Map<String,List<OrderExcuteLineVo>> voMap = new HashMap<>();
				for(OrderExcuteLineVo orderExcuteVo : orderExcuteVos) {
					Notice notice = noticeMap.get(orderExcuteVo.getWhCode() + orderExcuteVo.getInQualityControl());
					if(notice == null) {//20221123 wpp 下边判断增加accessType条件，out类型的操作不需要生成QualityClass检验单
						if(OrderEnums.AccessType.IN.getCode().equals(accessType)
								&& CommonEnums.YesNo.YES.getCode().equals(orderExcuteVo.getInQualityControl())
								&& ModuleUtils.contains("Quality")){//包括质量模块
							notice = new MoInQualityOrder();//(Notice) BeanReflectionUtils.newInstance(context.getQualityClass());
						}else{
							notice = (Notice) BeanReflectionUtils.newInstance(context.getNoticeClass());
						}

						notice.setBizOrderNo(order.getBizNo());
						notice.setNoticeDate(new Date());
						notice.setWhCode(orderExcuteVo.getWhCode());
						notice.setAccessType(accessType);
						notice.setPickingType(context.getPickingType());
						notice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CREATE.getStatusCode());
						// TODO 根据供应链策略判断是否产生申请单

						noticeMap.put(orderExcuteVo.getWhCode() + orderExcuteVo.getInQualityControl(), notice);
						voMap.put(orderExcuteVo.getWhCode() + orderExcuteVo.getInQualityControl(), new ArrayList<OrderExcuteLineVo>());
					}
					voMap.get(orderExcuteVo.getWhCode() + orderExcuteVo.getInQualityControl()).add(orderExcuteVo);
				}
				// 生成通知单明细
				for(Map.Entry<String,Notice> entry : noticeMap.entrySet()) {
					Notice notice = entry.getValue();
					if (notice instanceof MoInQualityOrder){
						((MoInQualityOrder)notice).setOrderType(order.getOrderType());//关联业务单类型
					}
					JpaUtil.save(notice);
					int lineNo = 0;
					for(OrderExcuteLineVo vo : voMap.get(entry.getKey())) {
						lineNo++;
						NoticeLine line = notice.createLine(vo);
						line.setSubLotIndex(vo.getSubLotIndex());
						line.setLineNo(lineNo+"");
						Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
						line.setItemName(item.getItemName());
						line.setItemSpec(item.getItemSpec());
						line.setUnitCode(item.getUnitCode());
						line.setDrawingNo(item.getDrawingNo());
						JpaUtil.save(line);
					}
				}
			}
			if(OrderStatusEnums.OrderStatus.PLAN.getStatusCode().equals(order.getOrderStatus())||
					OrderStatusEnums.OrderStatus.ORDERED.getStatusCode().equals(order.getOrderStatus())){
				order.setOrderStatus(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
				order.setExecuteTime(new Date());
				order.setExecutor(SecurityUtils.getLoginUsername());
				JpaUtil.update(order);
			}
			afterExecute(context);
		} else {
			if(CollectionUtils.isEmpty(context.getErrors())) {
				context.addError("前置校验不通过");
			}
		}
	}
	@Override
	public OrderContext config(OrderContext context) {
		context.setOrderExcuteVos(orderExcuteVos);
		context.setNoticeClass(MoInNotice.class);
		context.setQualityClass(MoInQualityOrder.class);//生产入库验收单
		context.setAccessType(OrderEnums.AccessType.IN.getCode());
		context.setPickingType(NoticeStatusEnums.NoticeType.MO_IN.getCode());
		return context;
	}

	@Override
	public boolean beforeExecute(OrderContext context) {
		Order order = context.getEntity();
		if (order instanceof ManufactureOrder && context.getOrderExcuteVos().size()>0){
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();

			List<ManufactureOrder> orderList = new ArrayList<>();
			orderList.add((ManufactureOrder) order);
			NoticeClassVo moInNoticeClazz = new NoticeClassVo(MoInNotice.class, MoInNoticeLine.class);//生产入库通知单
			NoticeClassVo moInQualityOrderClazz = new NoticeClassVo(MoInQualityOrder.class, MoInQualityOrderLine.class);//生产入库检验单
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(moInNoticeClazz);
			noticeClassVos.add(moInQualityOrderClazz);
			orderService.handleBizOrderQuantity(orderList,noticeClassVos,OrderEnums.AccessType.IN.getCode());

			BigDecimal executeTotal = BigDecimal.ZERO;//总执行数量，包含本次提交数量
			for(OrderExcuteLineVo orderExcuteVo : orderExcuteVos) {//此处执行是在生产订单主单行数据中执行，此处只有一条数据
				BigDecimal lineQuantity = orderExcuteVo.getLineQuantity();//实际等于主单 orderQuantity字段
				BigDecimal quantity = orderExcuteVo.getQuantity();
				ManufactureOrder manufactureOrder = orderList.get(0);
				BigDecimal actualQuantity = manufactureOrder.getActualQuantity();
				BigDecimal planQuantity = manufactureOrder.getPlanQuantity();
				BigDecimal lastMax = lineQuantity.subtract(actualQuantity).subtract(planQuantity);
				if (quantity.compareTo(lastMax)>0){
					context.addError("提交数据执行数量大于最大可执行数量【"+lastMax+"】。");
					return false;
				}
				executeTotal = executeTotal.add(quantity).add(actualQuantity);
			}
			//校验报工数量有没有大于已领料bom的最小成套数量
			List<ManufactureOrderItem> orderItemList = JpaUtil.linq(ManufactureOrderItem.class).equal("bizNo", order.getBizNo()).list();
			if (!orderItemList.isEmpty()){
				BigDecimal orderQuantity = ((ManufactureOrder) order).getOrderQuantity();//订单数量
				NoticeClassVo pickingNoticeClazz = new NoticeClassVo(MoPickingNotice.class, MoPickingNoticeLine.class);//领/补/退
				NoticeClassVo defectiveProductsNoticeClazz = new NoticeClassVo(DefectiveProductsNotice.class, DefectiveProductsNoticeLine.class);//不良品退料
				List<NoticeClassVo> orderItemNoticeClassVos = new ArrayList<>();
				orderItemNoticeClassVos.add(pickingNoticeClazz);
				orderItemNoticeClassVos.add(defectiveProductsNoticeClazz);
				orderLineService.handleBizOrderLineQuantity(orderItemList, orderItemNoticeClassVos, OrderEnums.AccessType.OUT.getCode());
				BigDecimal minSuit = BigDecimal.ZERO;
				String itemName = "";
				for (ManufactureOrderItem orderItem:orderItemList){
					BigDecimal actualQuantity = orderItem.getActualQuantity();//累计领料数量
					BigDecimal lineQuantity = orderItem.getQuantity();//行需求数量
					//行需求数量除以订单数量，得到单机耗用量，再用实际领料数量除以单机耗用量即为套数
					BigDecimal lineSuit = actualQuantity.multiply(orderQuantity).divide(lineQuantity, 6, BigDecimal.ROUND_HALF_UP);
					if (minSuit.compareTo(BigDecimal.ZERO)==0){
						minSuit = lineSuit;
						itemName = orderItem.getItemCode()+orderItem.getItemName();
					}else if (minSuit.compareTo(lineSuit)<0){
						minSuit = lineSuit;
						itemName = orderItem.getItemCode()+orderItem.getItemName();
					}
				}
				if (executeTotal.compareTo(minSuit)>0){
					context.addError("订单累计报工数量【"+executeTotal+"】大于订单bom明细中已领料【"+itemName+"】的最小套数【"+minSuit+"】。");
					return false;
				}
			}
		}
		return true;
	}

	@Override
	public void afterExecute(OrderContext context) {
		ManufactureOrder order = (ManufactureOrder) context.getEntity();
		List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();
		boolean completionFlag = false;
		for (OrderExcuteLineVo orderExcuteLineVo:orderExcuteVos){
			if(StringUtils.equals("1",orderExcuteLineVo.getCompletionFlag())){
				completionFlag = true;
				break;
			}
		}
		if (completionFlag){//报工执行，如果订单完工，则更新对应状态
			order.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
			order.setActualFinishDate(new Date());
			JpaUtil.update(order);
		}
	}

}
